#pragma once

namespace utility
{

template<typename T, typename O>
class function_0p
{
    typedef T (O::*fuction_type)();

    fuction_type func_;

public:

    typedef fuction_type value_type;

    function_0p(value_type f = 0) throw()
        : func_(f)
    {   }

    function_0p(const function_0p& fp) throw()
        : func_(fp.func_)
    {   }

    T operator()(O& obj) const
    {
        return (obj.*func_)();
    }

    bool empty() const throw()
    {
        return func_ == 0;
    }

    void clear() throw()
    {
        func_ = 0;
    }
};

template<typename T, typename O, typename P>
class function_1p
{
    typedef T (O::*fuction_type)(P);

    fuction_type func_;

public:

    typedef fuction_type value_type;

    function_1p(value_type f = 0) throw()
        : func_(f)
    {   }

    function_1p(const function_1p& fp) throw()
        : func_(fp.func_)
    {   }

    T operator()(O& o, P p) const
    {
        return (o.*func_)(p);
    }

    bool empty() const throw()
    {
        return func_ == 0;
    }

    void clear() throw()
    {
        func_ = 0;
    }
};

template<typename T, typename O, typename P1, typename P2>
class function_2p
{
    typedef T (O::*fuction_type)(P1, P2);

    fuction_type func_;

public:

    typedef fuction_type value_type;

    function_2p(value_type f = 0) throw()
        : func_(f)
    {   }

    function_2p(const function_2p& fp) throw()
        : func_(fp.func_)
    {   }

    T operator()(O& o, P1 p1, P2 p2) const
    {
        return (o.*func_)(p1, p2);
    }

    bool empty() const throw()
    {
        return func_ == 0;
    }

    void clear() throw()
    {
        func_ = 0;
    }
};

template<typename T, typename O, typename P1, typename P2, typename P3>
class function_3p
{
    typedef T (O::*fuction_type)(P1, P2, P3);

    fuction_type func_;

public:

    typedef fuction_type value_type;

    function_3p(value_type f = 0) throw()
        : func_(f)
    {   }

    function_3p(const function_3p& fp) throw()
        : func_(fp.func_)
    {   }

    T operator()(O& o, P1 p1, P2 p2, P3 p3) const
    {
        return (o.*func_)(p1, p2, p3);
    }

    bool empty() const throw()
    {
        return func_ == 0;
    }

    void clear() throw()
    {
        func_ = 0;
    }
};

} // namespace utility
